/**
 * oauth2认证路由
 *
 * Created by snowingsea on 2020/01/21.
 */
const auth = require('./../models/auth');
const users = require('./../models/users');
const encrypt = require('./../models/encrypt');
const PhoenixError = require('./../models/phoenix-error');
const { eventHub } = require('../models/event-hub');

/**
 * 使用密码授权
 * @param req
 * @param res
 * @param next
 */
function usePasswordGrant(req, res, next) {
  const { username, password } = req.body;
  if (!username || !password) {
    next(new PhoenixError('invalid request', 'Missing parameters. "username" and "password" are required'));
    return;
  }

  let userId;
  users.getUserByName(username)
    .then((user) => {
      if (!user) {
        return Promise.reject(new PhoenixError('not found', 'The user is not exists'));
      }
      userId = user._id; // eslint-disable-line no-underscore-dangle
      return encrypt.compare(password.toLowerCase(), user.salt, user.password);
    })
    .then((isPasswordMatch) => {
      if (!isPasswordMatch) {
        return Promise.reject(new PhoenixError('invalid grant', 'The username and the password do not match'));
      }
      return auth.generateAccessToken(userId);
    })
    .then((token) => {
      res.json({
        ...auth.getTokenJson(token),
        ...(req.$pangu || {}),
      });
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}
require('../models/pangu');

/**
 * 使用刷新令牌授权
 * @param req
 * @param res
 * @param next
 */
function useRefreshTokenGrant(req, res, next) {
  const { refreshToken, accessToken } = req.body;
  if (!refreshToken || !accessToken) {
    next(new PhoenixError('invalid request', 'Missing parameters. "refreshToken" and "accessToken" are required'));
    return;
  }

  auth.getToken(accessToken).then((token) => {
    if (!token || token.refreshToken !== refreshToken) {
      return Promise.reject(new PhoenixError('invalid grant', 'The refreshToken and the accessToken do not match'));
    }
    return auth.generateAccessToken(token.userId);
  }).then((token) => {
    res.json({
      ...auth.getTokenJson(token),
      ...(req.$pangu || {}),
    });
  }).catch((err) => {
    next(new PhoenixError(err));
  });
}

function qstAuthGrant(req, res, next) {
  (async () => {
    if (!req.body.code) {
      throw new PhoenixError('invalid request', 'Missing parameters. third party system code is required');
    }
    const userInfo = await users.getQstUser(req.body.code);
    const token = await auth.generateAccessToken(userInfo._id);
    res.json(auth.getTokenJson(token));
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}
function educoderAuthGrant(req, res, next) {
  (async () => {
    if (!req.body.username) {
      throw new PhoenixError('invalid request', 'Missing parameters. educoder username is required');
    }
    const userInfo = await users.geteducoderUser(req.body.username);
    const token = await auth.generateAccessToken(userInfo._id);
    res.json(auth.getTokenJson(token));
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

/**
 * 获取访问令牌
 * @param req
 * @param res
 * @param next
 */
async function getAccessToken(req, res, next) {
  await eventHub.emit('pangu_login', req);
  switch (req.body.grantType) {
    case 'password':
      usePasswordGrant(req, res, next);
      break;
    case 'refreshToken':
      useRefreshTokenGrant(req, res, next);
      break;
    case 'qst':
      qstAuthGrant(req, res, next);
      break;
    case 'educoder':
      educoderAuthGrant(req, res, next);
      break;
    default:
      next(new PhoenixError('invalid request', 'Invalid grantType parameter or parameter missing'));
      break;
  }
}

/**
 * Export model definition object.
 */
module.exports = (app, prefix) => {
  const oauth2Prefix = `${prefix}/oauth2`;

  app.post(`${oauth2Prefix}/access-token.json`, getAccessToken);
};
